package com.hjy.backend.dataManager;

import com.hjy.backend.dataManager.dataItem.DataItem;
import com.hjy.backend.dataManager.logger.Logger;
import com.hjy.backend.dataManager.logger.Recover;
import com.hjy.backend.dataManager.page.PageFirst;
import com.hjy.backend.dataManager.pageCache.PageCache;
import com.hjy.backend.transactionManager.TransactionManager;

public interface DataManager {
    /**
     * 根据 UID 从缓存中获取 DataItem，并校验有效位：
     *
     * @param uid
     * @return
     * @throws Exception
     */
    DataItem read(long uid) throws Exception;

    /**
     * 在 pageIndex 中获取一个足以存储插入内容的页面的页号，获取页面后，
     * 首先需要写入插入日志，接着才可以通过 pageNormal 插入数据，并返回插入位置的偏移。
     * 最后需要将页面信息重新插入 pageIndex。
     *
     * @param xid
     * @param data
     * @return
     * @throws Exception
     */
    long insert(long xid, byte[] data) throws Exception;

    void close();

    /**
     * 创造数据管理对象
     *
     * @param path
     * @param mem
     * @param tm
     * @return
     */
    public static DataManager create(String path, long mem, TransactionManager tm) {
        PageCache pc = PageCache.create(path, mem);
        Logger lg = Logger.create(path);

        DataManagerImpl dm = new DataManagerImpl(pc, lg, tm);
        // 初始化第一页
        dm.initPageFirst();
        return dm;
    }

    /**
     * 根据文件位置, 打开数据管理对象, 初始化 PageCache Logger
     *
     * @param path
     * @param mem
     * @param tm
     * @return
     */
    public static DataManager open(String path, long mem, TransactionManager tm) {
        // 初始化 PageCache, 加载 .db 文件
        PageCache pc = PageCache.open(path, mem);
        // 查看日志文件是否损坏, 加载 .log 文件
        Logger lg = Logger.open(path);
        DataManagerImpl dm = new DataManagerImpl(pc, lg, tm);
        // 在打开已有文件时时读入PageFirst，并验证正确性
        if (!dm.loadCheckPageFirst()) {
            // 第一页数据 100~107 与 108~115 数据不一致, 上一次是异常关闭, 恢复日志
            Recover.recover(tm, lg, pc);
        }
        // 初始化 pageIndex
        dm.fillPageIndex();
        // 随机一串字符放置到 100~107 的位置
        PageFirst.setVcOpen(dm.pageFirst);
        dm.pc.flushPage(dm.pageFirst);

        return dm;
    }
}
